<?php

namespace app\common\basic;

use app\common\exception\ApiException;
use think\facade\Db;

/**
 * 逻辑层基础类
 * @package app\service
 * @method static where($data) think-orm的where方法
 * @method static find($id) think-orm的find方法
 * @method static findOrEmpty($id) think-orm的findOrEmpty方法
 * @method static hidden($data) think-orm的hidden方法
 * @method static order($data) think-orm的order方法
 * @method static save($data) think-orm的save方法
 * @method static create($data) think-orm的create方法
 * @method static saveAll($data) think-orm的saveAll方法
 * @method static update($data, $where, $allow = []) think-orm的update方法
 * @method static select() think-orm的select方法
 * @method static count($data) think-orm的count方法
 * @method static max($data) think-orm的max方法
 * @method static min($data) think-orm的min方法
 * @method static sum($data) think-orm的sum方法
 * @method static avg($data) think-orm的avg方法
 */
class BaseLogic
{
    /**
     * @var object 模型注入
     */
    protected $model;
    
    /**
     * 表别名
     * @var string
     */
    protected $alias = '';
    
    /**
     * 默认排序
     * @var string|array
     */
    protected $defaultSort = '';
    
    /**
     * 排序字段
     * @var string
     */
    protected string $orderField = '';
    
    /**
     * 排序方式
     * @var string
     */
    protected string $orderType = 'ASC';
    
    /**
     * 设置排序字段
     * @param $field
     * @return void
     */
    public function setOrderField($field): void
    {
        $this->orderField = $field;
    }
    
    /**
     * 设置排序方式
     * @param $type
     * @return void
     */
    public function setOrderType($type): void
    {
        $this->orderType = $type;
    }
    
    /**
     * 数据库事务操作
     * @param callable $closure
     * @param bool $isTran
     * @return mixed
     */
    public function transaction(callable $closure, bool $isTran = true): mixed
    {
        return $isTran ? Db::transaction($closure) : $closure();
    }
    
    /**
     * 添加数据
     * @param $data
     * @return mixed
     */
    public function add($data): mixed
    {
        $this->model->save($data);
        return $this->model->getKey();
    }
    
    /**
     * 修改数据
     * @param $id
     * @param $data
     * @return mixed
     */
    public function edit($id, $data): mixed
    {
        $model = $this->model->findOrEmpty($id);
        if ($model->isEmpty()) {
            throw new ApiException('数据不存在');
        }
        return $model->save($data);
    }
    
    /**
     * 读取数据
     * @param $id
     * @return mixed
     */
    public function read($id): mixed
    {
        $model = $this->model->findOrEmpty($id);
        if ($model->isEmpty()) {
            throw new ApiException('数据不存在');
        }
        return $model;
    }
    
    /**
     * 删除数据
     * @param $ids
     */
    public function destroy($ids)
    {
        $this->model->destroy($ids);
    }
    
    /**
     * 搜索器搜索
     * @param array $searchWhere
     * @return mixed
     */
    public function search(array $searchWhere = []): mixed
    {
        $withSearch = array_keys($searchWhere);
        $data = $searchWhere;
        foreach ($withSearch as $k => $v) {
            if ($data[$v] === '') {
                unset($data[$v]);
                unset($withSearch[$k]);
            }
        }
        $query = $this->model;
        if (!empty($this->alias)) {
            $query = $query->alias($this->alias);
        }
        return $query->withSearch($withSearch, $data);
    }
    
    /**
     * 分页查询数据
     * @param $query
     * @return mixed
     */
    public function getList($query): mixed
    {
        return $this->buildQuery($query, false);
    }
    
    /**
     * 获取全部数据
     * @param $query
     * @return mixed
     */
    public function getAll($query): mixed
    {
        return $this->buildQuery($query, true);
    }
    
    /**
     * 公共查询构造器（分页/全部）
     * @param $query
     * @param bool $all
     * @return mixed
     */
    private function buildQuery($query, bool $all = false): mixed
    {
        $alias     = $this->alias ?: '';
        $orderBy   = trim(request()->input('orderBy', ''));
        $orderType = request()->input('orderType', $this->orderType);
        $saiColumn = request()->input('saiColumn', '');
        
        /* 动态字段：自动追加表别名 + 校验 */
        if ($saiColumn !== '') {
            $fields = array_map('trim', explode(',', $saiColumn));
            $valid  = [];
            foreach ($fields as $f) {
                if ($f === '' || !$this->isValidField($f)) continue;
                $valid[] = str_contains($f, '.') ? $f : ($alias ? "$alias.$f" : $f);
            }
            if ($valid) $query->field($valid);
        }
        
        if (!empty($this->scope) && method_exists($this, 'userDataScope')) {
            $query = $this->userDataScope($query);
        }
        
        /* 排序字段：别名自动补全 */
        $useUserOrder = false;
        
        if ($orderBy !== '' && $this->isValidField($orderBy)) {
            $orderBy = !str_contains($orderBy, '.') && $alias
                ? "$alias.$orderBy"
                : $orderBy;
            
            $query->order($orderBy, $orderType);
            $useUserOrder = true;
        }
        
        if (!$useUserOrder && !empty($this->defaultSort)) {
            $this->applyDefaultSort($query, $alias);
        }
  
        return $all
            ? $query->select()->toArray()
            : $query->paginate(
                request()->input('limit', 10),
                false,
                ['page' => request()->input('page', 1)]
            )->toArray();
    }
    
    /**
     * 验证字段是否合法
     * @param string $field
     * @return bool
     */
    protected function isValidField(string $field): bool
    {
        return preg_match('/^[a-zA-Z0-9_.]+$/', $field) === 1;
    }
    
    /**
     * 应用默认排序
     * @param $query
     * @param string $alias
     */
    private function applyDefaultSort($query, string $alias): void
    {
        $sort = is_string($this->defaultSort)
            ? (str_contains($this->defaultSort, ',')
                ? array_map('trim', explode(',', $this->defaultSort))
                : [$this->defaultSort => $this->orderType])
            : (array)$this->defaultSort;
        
        foreach ($sort as $field => $type) {
            if (is_int($field)) [$field, $type] = [$type, $this->orderType];
            $field = !str_contains($field, '.') && $alias ? "$alias.$field" : $field;
            if ($this->isValidField($field)) $query->order($field, $type);
        }
    }
    
    /**
     * 获取上传的导入文件
     * @param $file
     * @return string
     */
    public function getImport($file): string
    {
        $full_dir = runtime_path() . '/resource/';
        if (!is_dir($full_dir)) {
            mkdir($full_dir, 0777, true);
        }
        $ext = $file->getUploadExtension() ?: null;
        $full_path = $full_dir . md5(time()) . '.' . $ext;
        $file->move($full_path);
        return $full_path;
    }
    
    /**
     * 方法调用
     * @param $name
     * @param $arguments
     * @return mixed
     */
    public function __call($name, $arguments)
    {
        return call_user_func_array([$this->model, $name], $arguments);
    }
}